﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Configuration;
using System.Messaging;
using System.Web.Script.Serialization;

namespace CometTester
{

    public class TestResultItem
    {
        public double TimeTakenInMilliseconds;
        public int RepsFailed;
        public int WcfFailures;
    }

    public class CometConnectionEventArgs : EventArgs
    {

    }

    public class CometTester
    {

        private int _id;
        private ManualResetEvent _doneEvent;
        private string _message;
        private int _repsPerTest;
        private TestResultItem _result = new TestResultItem();
        private int _waitTime = 0;

        public int ID { get { return _id; } }
        public TestResultItem TestResults { get { return _result; } }

        public event EventHandler<CometConnectionEventArgs> CometConnectionEvent;

        public CometTester(int id, ManualResetEvent doneEvent, string message, int repsPerTest, int waitTime)
        {
            _id = id;
            _doneEvent = doneEvent;
            _message = message;
            _repsPerTest = repsPerTest;
            _result.RepsFailed = 0;
            _result.WcfFailures = 0;
            _waitTime = waitTime;
        }

        #region Synchronous Test Methods

        public void SingleCometRoundtrip()
        {
            Thread.Sleep(1000);

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(ConfigurationManager.AppSettings["CometServerUrl"]);

            byte[] bytes;
            using (Stream reader = File.OpenRead("Data.xml"))
            {
                bytes = new byte[reader.Length];
                reader.Read(bytes, 0, (int)reader.Length);
            }

            request.SendChunked = false;
            request.KeepAlive = true;
            request.Credentials = new NetworkCredential("server", "server123");
            request.Method = "GET";
            //request.ContentType = "application/xml";
            request.ContentType = "text/json";
            request.ContentLength = bytes.Length - 3;

            Stream stream = request.GetRequestStream();
            stream.Write(bytes, 3, bytes.Length - 3);


            //Console.WriteLine(System.Text.Encoding.ASCII.GetString(bytes));

            string messageReturned;

            try
            {
                HttpWebResponse res = (HttpWebResponse)request.GetResponse();
                StreamReader s = new StreamReader(res.GetResponseStream());
                messageReturned = s.ReadToEnd();
                s.Close();
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());

            }
            stream.Close();


        }


        public void EngageCometBroadcast(Object threadContext)
        {

            int threadIndex = (int)threadContext;

            //Thread.Sleep(1000);


            string messageReturned;
            StreamReader s;
            bool testPassed = true;

            for (int i = 0; i < _repsPerTest; i++)
            {
                try
                {

                    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(ConfigurationManager.AppSettings["CometServerUrl"]);

                    byte[] bytes;
                    UTF8Encoding encoding = new UTF8Encoding();
                    bytes = encoding.GetBytes(_message);

                    request.SendChunked = false;
                    request.KeepAlive = true;
                    request.Credentials = new NetworkCredential("server", "server123");
                    request.Method = "POST";
                    //request.ContentType = "application/xml";
                    request.ContentType = "text/json";
                    request.ContentLength = bytes.Length;
                    request.KeepAlive = true;

                    Stream stream = null;

                    stream = request.GetRequestStream();
                    stream.Write(bytes, 0, bytes.Length);
                    try
                    {
                        //MsgQService.CallCometServiceClient callCometClient = new MsgQService.CallCometServiceClient();
                        //callCometClient.SendCometMessage(_message);
                        //callCometClient.Close();
                    }
                    catch (Exception ex)
                    {
                        _result.WcfFailures++;
                        Trace.WriteLine(ex.ToString());
                        continue;
                    }
                    Thread.Sleep(_waitTime);
                    DateTime startTime = DateTime.Now;
                    HttpWebResponse res = (HttpWebResponse)request.GetResponse();
                    s = new StreamReader(res.GetResponseStream());
                    messageReturned = s.ReadToEnd();
                    s.Close();
                    res.Close();
                    DateTime endTime = DateTime.Now;
                    double singleCometResponse = endTime.Subtract(startTime).TotalMilliseconds;
                    _result.TimeTakenInMilliseconds += endTime.Subtract(startTime).TotalMilliseconds;
                    if (String.IsNullOrEmpty(messageReturned))
                    {
                        //failed.
                        _result.RepsFailed++;
                    }
                    stream.Close();

                }
                catch (Exception ex)
                {
                    testPassed = false;
                    Trace.WriteLine(ex.ToString());
                    _result.RepsFailed++;

                }
            }

            _result.TimeTakenInMilliseconds = _result.TimeTakenInMilliseconds / _repsPerTest;

            _doneEvent.Set();


        }


        public void PingComet(Object threadContext)
        {

            int threadIndex = (int)threadContext;

            //Thread.Sleep(1000);


            string messageReturned;
            StreamReader s;
            bool testPassed = true;

            for (int i = 0; i < _repsPerTest; i++)
            {
                try
                {

                    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(ConfigurationManager.AppSettings["CometServerUrl"]);

                    byte[] bytes;
                    UTF8Encoding encoding = new UTF8Encoding();
                    bytes = encoding.GetBytes(_message);

                    request.SendChunked = false;
                    request.KeepAlive = true;
                    request.Credentials = new NetworkCredential("server", "server123");
                    request.Method = "POST";
                    //request.ContentType = "application/xml";
                    request.ContentType = "text/ping";
                    request.ContentLength = bytes.Length;
                    request.KeepAlive = true;

                    Stream stream = null;

                    stream = request.GetRequestStream();
                    stream.Write(bytes, 0, bytes.Length);
                    Thread.Sleep(_waitTime);
                    DateTime startTime = DateTime.Now;
                    HttpWebResponse res = (HttpWebResponse)request.GetResponse();
                    DateTime endTime = DateTime.Now;
                    s = new StreamReader(res.GetResponseStream());
                    messageReturned = s.ReadToEnd();
                    s.Close();
                    res.Close();
                    double singleCometResponse = endTime.Subtract(startTime).TotalMilliseconds;
                    _result.TimeTakenInMilliseconds += endTime.Subtract(startTime).TotalMilliseconds;
                    if (String.IsNullOrEmpty(messageReturned))
                    {
                        //failed.
                        _result.RepsFailed++;
                    }
                    stream.Close();

                }
                catch (Exception ex)
                {
                    testPassed = false;
                    Trace.WriteLine(ex.ToString());
                    _result.RepsFailed++;

                }
            }

            _result.TimeTakenInMilliseconds = _result.TimeTakenInMilliseconds / _repsPerTest;

            _doneEvent.Set();


        }

        #endregion Synchronous Test Methods


        #region Asynchronous Test Methods

        private ManualResetEvent _asyncCallDone = new ManualResetEvent(false);

        public void AsyncPing(Object threadContext)
        {
            int threadIndex = (int)threadContext;

            Uri cometSite = new Uri(ConfigurationManager.AppSettings["CometServerUrl"]);
            WebRequest wreq = WebRequest.Create(cometSite);
            RequestState rs = new RequestState();
            byte[] bytes;
            UTF8Encoding encoding = new UTF8Encoding();
            bytes = encoding.GetBytes(_message);

            wreq.Credentials = new NetworkCredential("server", "server123");
            wreq.Method = "POST";
            //request.ContentType = "application/xml";
            wreq.ContentType = "text/json";
            wreq.ContentLength = bytes.Length;

            rs.Request = wreq;
            rs.StartTime = DateTime.Now;
            IAsyncResult r = (IAsyncResult)wreq.BeginGetResponse(new AsyncCallback(asyncPingCallback), rs);
            //_asyncCallDone.WaitOne();
            _doneEvent.Set();
        }

        private void asyncPingCallback(IAsyncResult ar)
        {
            RequestState rs = (RequestState)ar.AsyncState;
            WebRequest req = rs.Request;
            WebResponse resp = req.EndGetResponse(ar);
            DateTime endTime = DateTime.Now;
            _result.TimeTakenInMilliseconds = endTime.Subtract(rs.StartTime).TotalMilliseconds;
            //Stream responseStream = resp.GetResponseStream();

        }


        //Async call that includes transmitting message via message queue:

        public void AsyncTest(Object threadContext)
        {
            int threadIndex = (int)threadContext;

            Uri cometSite = new Uri(ConfigurationManager.AppSettings["CometServerUrl"]);
            WebRequest wreq = WebRequest.Create(cometSite);
            RequestState rs = new RequestState();
            byte[] bytes;
            UTF8Encoding encoding = new UTF8Encoding();
            bytes = encoding.GetBytes("Open sesame.");

            wreq.Credentials = new NetworkCredential("server", "server123");
            wreq.Method = "POST";
            //request.ContentType = "application/xml";
            wreq.ContentType = "text/json";
            wreq.ContentLength = bytes.Length;
            Stream requestStream = wreq.GetRequestStream();
            requestStream.Write(bytes, 0, bytes.Length);

            rs.Request = wreq;
            rs.StartTime = DateTime.Now;

            //EventHandler<CometConnectionEventArgs> handler = CometConnectionEvent;

            //if (handler != null)
            //{
            //    handler(this, new CometConnectionEventArgs());
            //}

            IAsyncResult r = (IAsyncResult)wreq.BeginGetResponse(new AsyncCallback(asyncTestCallback), rs);

            //_asyncCallDone.WaitOne();
            //_doneEvent.Set();

        }

        private void asyncTestCallback(IAsyncResult ar)
        {
            RequestState rs = (RequestState)ar.AsyncState;
            WebRequest req = rs.Request;
            WebResponse resp = null;
            try
            {
                resp = req.EndGetResponse(ar);
            }
            catch (Exception ex)
            {
                _result.RepsFailed++;
                _doneEvent.Set();
                return;
            }
            DateTime endTime = DateTime.Now.ToUniversalTime();
            Stream responseMessageStream = resp.GetResponseStream();

            JavaScriptSerializer jsonSerializer = null;

            StreamReader responseMessageReader = new StreamReader(responseMessageStream);
            string responseMessageStr = responseMessageReader.ReadToEnd();

            try
            {
                jsonSerializer = new JavaScriptSerializer();
            }
            catch (Exception ex)
            {
                _result.RepsFailed++;
                _doneEvent.Set();
                return;
            }
            //_result.TimeTakenInMilliseconds = endTime.Subtract(rs.StartTime).TotalMilliseconds;
            //Stream responseStream = resp.GetResponseStream();

            ClientMessage3 responseMessage = jsonSerializer.Deserialize<ClientMessage3>(responseMessageStr);
            _result.TimeTakenInMilliseconds += endTime.Subtract(responseMessage.SendTimestamp).TotalMilliseconds;

            //_asyncCallDone.Set();
            _doneEvent.Set();

        }

        public void DumpMessage(Object threadContext)
        {
            try
            {
                //_cometServer.BroadcastMessage(_sendCometMsgTextBox.Text);
                string msgQueueName = ConfigurationManager.AppSettings["CometQueue"];
                MessageQueue testMessageQueue = new MessageQueue(msgQueueName);
                System.Messaging.Message msg = new System.Messaging.Message(_message, new XmlMessageFormatter(new Type[] { typeof(string) }));
                testMessageQueue.Send(msg);
            }
            catch (Exception ex)
            {
                string error = ex.ToString();
                //Response.Write(error);
                throw ex;
            }

        }



        #endregion Asynchronous Test Methods



    }

    public class RequestState
    {
        const int BufferSize = 1024;
        public StringBuilder RequestData;
        public byte[] BufferRead;
        public WebRequest Request;
        public Stream ResponseStream;
        // Create Decoder for appropriate enconding type.
        public Decoder StreamDecode = Encoding.UTF8.GetDecoder();
        public DateTime StartTime;

        public RequestState()
        {
            BufferRead = new byte[BufferSize];
            RequestData = new StringBuilder(String.Empty);
            Request = null;
            ResponseStream = null;
        }
    }

    public class ClientMessage3
    {
        public DateTime SendTimestamp { get; set; }
        public string Browser { get; set; }
        public string Message { get; set; }
    }

}
